home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 22
/
Cream of the Crop 22.iso
/
program
/
cgazv4n3.zip
/
GETESTR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-05
|
13KB
|
378 lines
/**************** GETESTR.C *************
Get an editable string
(c) Copyright 1989, The C Gazette
Use freely as long as authorship is acknowledged
Andrew Binstock v. 1.4
Validated for MSC, Turbo C
***************************************/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#define DRIVER 1 /* Enables running main() as a demo */
#define HOME 0x4700 /* Special Case - Editing Keys */
#define S_HOME 0x4737
#define C_HOME 0x7700
#define END 0x4F00
#define S_END 0x4F31
#define C_END 0x7500
#define ESC 0x011B
#define ENTER 0x1C0D
#define LEFT 0x4B00
#define RIGHT 0x4D00
#define BACKSP 0x0E08
#define INSERT 0x5200
#define DELETE 0x5300
#define TAB_KEY 0x0F09
#define BK_TAB 0x0F00
#define TABSIZE 8
#define TAB 0x09
#define Insert 1
#define Overwrite 0
#define ON 1 /* For hiding/showing the cursor */
#define OFF 0
#define LINE 2 /* For cursor shape on Ins/Ovrwr */
#define BLOCK 3
#define update_cursor() set_cursor(pos, srow, scol)
#define update_line() set_cursor(pos, srow, scol); cputs((char *)(buff+pos))
static int Shape;
static void set_cursor(int, int, int);
static void cursor(int);
int get_basic_video_type(void);
char * getestr(char * const curr, /* current string, if any */
int srow, int scol, /* starting location */
size_t slen, /* maximum string length */
char insert_mode /* start in Ins or Ovrwrite */
)
{
union REGS inregs, outregs;
int i, j, c, done, pos;
char *buff;
done = 0;
buff = (char *) calloc(1, slen + 1); /* Our buffer */
/* position cursor at row, col */
set_cursor(0, srow, scol);
i = j = 0;
/* copy slen chars of curr to screen */
if (*curr != NULL)
for (;j < slen && curr[i]; i++, j++) /* i = char in */
{ /* j = char out */
if (curr[i] == TAB)
{ /* expand tabs to TABSIZE */
int cols_to_go = TABSIZE - (j % TABSIZE);
do
{
putch(' ');
buff[j] = ' ';
j++;
}
while (j < slen && --cols_to_go > 0);
j--; /* We're at the next column, so back up 1 */
}
else
{ /* If it's not a tab just write it out */
putch(curr[i]);
buff[j] = curr[i];
}
}
while (j < slen) /* Pad the string with spaces */
buff[j++] = ' ';
buff[slen] = '\0';
pos = 0; /* Move cursor to start of string */
update_cursor();
while (!done) /* Process keystrokes until done */
{
inregs.h.ah = 0x0; /* get key */
int86(0x16, &inregs, &outregs);
switch (outregs.x.ax) /* contains scan-code - ASCII code */
{
case HOME:
case S_HOME:
case C_HOME:
pos = 0;
update_cursor();
break;
case END:
case S_END:
case C_END:
for (pos = slen - 1; pos >= 0; pos--)
if (pos == 0 || isgraph(buff[pos]))
break;
if (pos != slen - 1)
pos += 1; /* one char beyond EOS */
update_cursor();
break;
case ESC:
case ENTER:
done = 1;
break;
case LEFT:
if (pos > 0)
pos--;
update_cursor();
break;
case RIGHT:
if (pos < slen - 1)
pos++;
update_cursor();
break;
case BACKSP:
if (pos == 0)
break;
if (insert_mode == Overwrite)
/* In overwrite mode, */
{ /* just blank char at left */
buff[--pos] = ' ';
cursor(OFF);
update_line();
update_cursor();
cursor(ON);
}
else
{
cursor(OFF);
for (i = slen - 1; i >= 0; i--)
if (i == 0 || isgraph(buff[i]))
break;
pos--;
strcpy((void *) (buff + pos), (void *) (buff + pos + 1));
buff[slen - 1] = ' ';
update_line();
update_cursor();
cursor(ON);
}
break;
case TAB_KEY:
{
int cols_to_go = (TABSIZE - pos % TABSIZE);
if (insert_mode == Overwrite) /* just move the cursor */
{
if ((pos += cols_to_go) > slen - 1)
pos = slen - 1;
update_cursor();
}
else /* otherwise insert spaces */
{
int k;
for (i = slen - 1; i >= 0; i--) /* how many spaces */
if (i == 0 || isgraph(buff[i])) /* at end of buff? */
break;
j = min (cols_to_go, (slen - 1) - i); /* insert the */
memmove ((void *) (buff + pos + j - 1),/* lesser of cols_ */
(void *) (buff + pos - 1), /* to_go and # of */
slen - pos); /* spaces left. */
buff[slen] = '\0';
cursor (OFF);
for (k=j; j >= 0; j--)
buff [pos+j - 1] = ' ';
update_line();
pos += k;
update_cursor();
cursor(ON);
}
}
break;
case BK_TAB: /* back tab -- only moves the cursor */
{
int cols_to_go = pos % TABSIZE;
if (cols_to_go == 0)
cols_to_go = TABSIZE;
if ((pos -= cols_to_go) < 0)
pos = 0;
update_cursor();
}
break;
case DELETE:
{
cursor(OFF);
for (i = slen - 1; i >= 0; i--) /* Find last non-space */
if (i == 0 || isgraph(buff[i])) /* in the string. */
break;
strcpy((void *) (buff + pos), (void *) (buff + pos + 1));
buff[slen - 1] = ' ';
update_line();
update_cursor();
cursor(ON);
}
break;
case INSERT:
if (insert_mode == Overwrite)
{
insert_mode = Insert;
Shape = BLOCK;
}
else
{
insert_mode = Overwrite;
Shape = LINE;
}
cursor(ON);
break;
default: /* print any printable character */
{
if (!(pos < slen)) /* If beyond EOL, beep */
{
putchar('\a');
break;
}
if (isprint(c=outregs.h.al))
{
if (insert_mode == Overwrite)
{
buff[pos] = (char) c;
cursor(OFF);
update_line();
pos++;
update_cursor();
cursor(ON);
}
else /* mode is Insert */
{
if (! isspace(buff[slen-1]))
{
putchar('\a');
break;
}
else
{ /* memcpy won't work --- overlapping move */
memmove((void *) (buff + pos + 1),
(void *) (buff + pos),
slen - pos - 1);
buff[slen] = '\0';
buff[pos] = (char) c;
cursor(OFF);
update_line();
pos++;
update_cursor();
cursor(ON);
}
}
break;
}
} /* end of default */
} /* end of switch */
} /* end of while */
strcpy(curr, buff);
return (curr);
}
static void set_cursor(int col, int offset_row, int offset_col)
{ /* set cursor position: int 10h, service 2 */
union REGS inregs, outregs;
static int page = -1;
if (page == -1) /* Since page cannot be -1 */
{ /* this will be done once */
inregs.h.ah = 0xF;
int86(0x10, &inregs, &outregs);
page = outregs.h.bh;
}
inregs.h.ah = 0x02;
inregs.h.dh = (char) offset_row;
inregs.h.dl = (char) col + offset_col;
inregs.h.bh = (char) page;
int86(0x10, &inregs, &outregs);
}
static void cursor(int status) /* Cursor on/off function */
{
union REGS inregs, outregs;
static unsigned int top, bottom; /* cursor scan lines */
if ((top | bottom) == 0) /* if neither of them has been identified */
{ /* only executed the first time through */
switch (get_basic_video_type())
{
/* top and bottom are the */
case 1: /* MDA */ /* scan lines for the cursor */
/* when it appears as an un- */
default: /* derscore. If the cursor is*/
top = 12; /* a block the value of top */
bottom = 13; /* is zero. This is due to */
break; /* the way scan lines are */
case 2: /* CGA */ /* numbered: 0 to n, where 0 */
case 3: /* EGA */ /* is the topmost line. */
top = 6;
bottom = 7;
break;
case 4: /* VGA */
top = 13;
bottom = 14;
break;
}
}
inregs.h.ah = 0x1; /* Service to set cursor size */
inregs.h.cl = (char) bottom;
inregs.h.ch = (char) (Shape == BLOCK ? 0 : top);
if (status == OFF)
inregs.h.ch |= 0x10; /* When bit 4 is on cursor is hidden */
int86(0x10, &inregs, &outregs);
}
int get_basic_video_type(void) /* Very broad test for basic video type. */
{ /* For more details on the technique, see */
union REGS inregs, outregs; /* my article, "Identifying Video Systems", */
/* in The C Gazette, Vol 4, No. 1 */
inregs.h.ah = 0x1A;
inregs.h.al = 0x0;
int86(0x10, &inregs, &outregs);
if (outregs.h.al == 0x1A) /* True for VGA and MCGA */
return 4;
inregs.h.ah = 0x12;
inregs.h.bl = 0x10;
int86(0x10, &inregs, &outregs);
if (outregs.h.bl != 0x10) /* True for EGA */
return 3;
inregs.h.ah = 0xF;
int86(0x10, &inregs, &outregs);
if (outregs.h.al == 0x7) /* True for mono */
return 1;
else
return 2; /* else it's a CGA */
}
#ifdef DRIVER /* Test driver for routine */
int main (void)
{
char *pp;
static char * p = "this is the forest prime";
pp = getestr(p, 10, 10, 28, Overwrite);
putchar('\n');
puts(pp);
return (0);
}
#endif